package com.x.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;

import com.x.model.Location;

@Component
public class LocationDAO extends BaseDAO {
	public Map<String, Object> list(int pageIndex, int pageSize,
			List<String> wherePart, List<String[]> odrerPart) {

		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("type", "3"));
		c.setProjection(Projections.rowCount());
		Object total = c.uniqueResult();
		if (!wherePart.isEmpty()) {
			c = c.add(Restrictions.like("name", wherePart.get(2),
					MatchMode.ANYWHERE));
		}
		for (String[] order : odrerPart) {
			if (order[0].equals("district")) {
				if (order[1].equals("desc")) {
					c.addOrder(Order.desc("name"));
				} else {
					c.addOrder(Order.asc("name"));
				}
			}
		}
		c = c.createCriteria("parent");
		if (!wherePart.isEmpty() && !wherePart.get(1).isEmpty()) {
			c = c.add(Restrictions.like("name", wherePart.get(1),
					MatchMode.ANYWHERE));
		}
		for (String[] order : odrerPart) {
			if (order[0].equals("city")) {
				if (order[1].equals("desc")) {
					c.addOrder(Order.desc("name"));
				} else {
					c.addOrder(Order.asc("name"));
				}
			}
		}
		c = c.createCriteria("parent");
		if (!wherePart.isEmpty() && !wherePart.get(0).isEmpty()) {
			c = c.add(Restrictions.like("name", wherePart.get(0),
					MatchMode.ANYWHERE));
		}
		for (String[] order : odrerPart) {
			if (order[0].equals("province")) {
				if (order[1].equals("desc")) {
					c.addOrder(Order.desc("name"));
				} else {
					c.addOrder(Order.asc("name"));
				}
			}
		}

		Object recordsFiltered = c.uniqueResult();
		c.setProjection(null);
		c.setFirstResult(pageIndex);
		c.setMaxResults(pageSize);
		List<Location> locations = c.list();

		List<String[]> datas = new ArrayList();
		for (Location location : locations) {
			String district = location.getName();
			String id = location.getId();
			String city = location.getParent().getName();
			String province = location.getParent().getParent().getName();
			String data[] = { province, city, district, id };
			datas.add(data);
		}

		Map<String, Object> result = new HashMap<String, Object>();
		result.put("recordsTotal", total);
		result.put("recordsFiltered", recordsFiltered);
		result.put("data", datas);
		return result;
	}

	private Location getCityByProvince(String province, String city) {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("name", city));
		c = c.add(Restrictions.eq("type", "2"));
		c = c.createCriteria("parent");
		c = c.add(Restrictions.eq("name", province));
		c = c.add(Restrictions.eq("type", "1"));
		return (Location) c.uniqueResult();
	}

	public void create(String province, String city, String district) {
		Location provinceLocation = getNode(province, "1");
		if (provinceLocation == null) {
			provinceLocation = new Location();
			provinceLocation.setName(province);
			provinceLocation.setType("1");
			Location root = getRoot();
			provinceLocation.setParent(root);
			this.getSession().merge(provinceLocation);
			provinceLocation = getNode(province, "1");
			Location cityLocation = new Location();
			cityLocation.setName(city);
			cityLocation.setParent(provinceLocation);
			cityLocation.setType("2");
			this.getSession().merge(cityLocation);
			cityLocation = getCityByProvince(province, city);
			Location districtLocation = new Location();
			districtLocation.setName(district);
			districtLocation.setParent(cityLocation);
			districtLocation.setType("3");
			this.getSession().merge(districtLocation);
		} else {
			Location cityLocation = getCityByProvince(province, city);
			if (cityLocation == null) {
				cityLocation = new Location();
				cityLocation.setName(city);
				cityLocation.setParent(provinceLocation);
				cityLocation.setType("2");
				this.getSession().merge(cityLocation);
				cityLocation = getCityByProvince(province, city);
				Location districtLocation = new Location();
				districtLocation.setName(district);
				districtLocation.setParent(cityLocation);
				districtLocation.setType("3");
				this.getSession().merge(districtLocation);
			} else {
				Location districtLocation = new Location();
				districtLocation.setName(district);
				districtLocation.setParent(cityLocation);
				districtLocation.setType("3");
				this.getSession().merge(districtLocation);
			}
		}

	}

	private Location getRoot() {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("type", "0"));
		Location root = (Location) c.uniqueResult();
		return root;
	}

	public List<Location> getNodeSuggest(String name, String type) {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.like("name", name, MatchMode.ANYWHERE));
		if (!type.isEmpty()) {
			c = c.add(Restrictions.eq("type", type));
		}
		return (List<Location>) c.list();
	}

	// just for province and city
	public Location getNode(String name, String type) {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("name", name));
		c = c.add(Restrictions.eq("type", type));
		return (Location) c.uniqueResult();
	}

	public Location getNodeById(String id) {
		Location location = (Location) this.getSession()
				.get(Location.class, id);
		return location;
	}

	public List<Location> getLocationByType(String type, int limit) {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("type", type));
		if (limit > 0) {
			c.setFirstResult(0);
			c.setMaxResults(limit);
		}
		return (List<Location>) c.list();
	}

	public boolean notExsit(String province, String city, String district) {
		Criteria c = this.getSession().createCriteria(Location.class);
		c = c.add(Restrictions.eq("name", district));
		c = c.add(Restrictions.eq("type", "3"));
		c = c.createCriteria("parent");
		c = c.add(Restrictions.eq("name", city));
		c = c.add(Restrictions.eq("type", "2"));
		c = c.createCriteria("parent");
		c = c.add(Restrictions.eq("name", province));
		c = c.add(Restrictions.eq("type", "1"));
		return c.list().isEmpty();
	}
	

	public void delete(String id) {
		Location districtLocation = getNodeById(id);
		Location cityLocation = districtLocation.getParent();
		Location provinceLocation = cityLocation.getParent();
		cityLocation.getChildren().remove(districtLocation);
		districtLocation.setParent(null);
		this.getSession().delete(districtLocation);
		if (cityLocation.getChildren().isEmpty()) {
			provinceLocation.getChildren().remove(cityLocation);
			cityLocation.setParent(null);
			this.getSession().delete(cityLocation);

			if (provinceLocation.getChildren().isEmpty()) {
				Location root = getRoot();
				root.getChildren().remove(provinceLocation);
				provinceLocation.setParent(null);
				this.getSession().delete(provinceLocation);
			}
		}
	}

	public void update(String province, String city, String district, String id) {
		//delete(id);
		Location districtLocation = getNodeById(id);
		//districtLocation.setParent(null);
		Location cityDelLocation = districtLocation.getParent();
		Location provinceDelLocation = cityDelLocation.getParent();
		if (notExsit(province, city, district)) {
			Location provinceLocation = getNode(province, "1");
			if (provinceLocation == null) {
				provinceLocation = new Location();
				provinceLocation.setName(province);
				provinceLocation.setType("1");
				Location root = getRoot();
				provinceLocation.setParent(root);
				this.getSession().merge(provinceLocation);
				provinceLocation = getNode(province, "1");
				cityDelLocation.getChildren().remove(districtLocation);
				Location cityLocation = new Location();
				cityLocation.setName(city);
				cityLocation.setParent(provinceLocation);
				cityLocation.setType("2");
				this.getSession().merge(cityLocation);				
				cityLocation = getCityByProvince(province, city);
				districtLocation.setName(district);
				districtLocation.setParent(cityLocation);
				districtLocation.setType("3");
				this.getSession().merge(districtLocation);
				
			} else {
				Location cityLocation = getCityByProvince(province, city);
				if (cityLocation == null) {
					cityDelLocation.getChildren().remove(districtLocation);
					cityLocation = new Location();
					cityLocation.setName(city);
					cityLocation.setParent(provinceLocation);
					cityLocation.setType("2");
					this.getSession().merge(cityLocation);
					cityLocation = getCityByProvince(province, city);
					districtLocation.setName(district);
					districtLocation.setParent(cityLocation);
					districtLocation.setType("3");
					this.getSession().merge(districtLocation);
				} else {
					if(!cityLocation.equals(cityDelLocation)){
						cityDelLocation.getChildren().remove(districtLocation);
					}
					districtLocation.setName(district);
					districtLocation.setParent(cityLocation);
					districtLocation.setType("3");
					this.getSession().merge(districtLocation);
				}
			}
		}
		if(cityDelLocation.getChildren().isEmpty()){
			provinceDelLocation.getChildren().remove(cityDelLocation);
			cityDelLocation.setParent(null);
			this.getSession().delete(cityDelLocation);
			if(provinceDelLocation.getChildren().isEmpty()){
				Location root = getRoot();
				root.getChildren().remove(provinceDelLocation);
				provinceDelLocation.setParent(null);
				this.getSession().delete(provinceDelLocation);
			}
		}
	}
}
